{\rtf0\ansi{\fonttbl\f0\fmodern Courier;}
\paperw11780
\paperh9020
\margl120
\margr20
{\colortbl;\red0\green0\blue255;\red255\green0\blue0;\red0\green0\blue0;}
\pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\f0\b0\i0\ulnone\fs24\fc0\cf0 #import "UndoManager.h"\
\

\gray108\fc1\cf1 /******************************************************************************\

\b UndoManager\

\b0 \
	The UndoManager object is used to handle undo and redo on a document basis in an application. Objects in the application register changes to themselves by sending an "undo" message to an undoManager instance from within an undoable method.For Example:\
	\
	- setRadius:(float)value\
	\{\

\b 		// Give undoManager the target for this event, then send undo message.\

\b0 		[[undoManager setUndoTarget:self] setRadius:radius];\
	\

\b 		// Set the new value and return\

\b0 		radius = value; return self;\
	\}\
	\
	The UndoManager keeps a group (or list) of records for each "undoable" change. Each record contains a pointer to an object, an action for that object to perform and the arguments for that action. Undo is achieved by executing the target/action information in these undo records.\
	\
	To add several records to an undo group, enclose the registration messages between UndoManager's -beginUndoRecordGrouping and -endUndoRecordGrouping methods. Undo messages that are not surrounded by these methods are added to the undoList in a group by themselves.\
\
	Also since sometimes changes should be ignored (ie. all of the discrete movements of a shape in a drag loop should not be undoable, just the final overall move), the messages -disableUndoRegistration and -reenableUndoRegistration can be sent to control which events are accepted into an undo record. For example, you might call [undoManager disableUndoRegistration] on a mouseDown: to prevent methods that register themselves with the undoManager to register each mouse drag, then you would call [undoManager reenableUndoRegistration] on mouseUp: with another call that would undo the drag loop (ie, [undoManager moveSelectedObjectsTo:oldPoint]).\
\
	The UndoManager allows the User to set the number of levels of undo to maintain (-setLevelsOfUndo:). When the number of records exceeds this amount, the excess is removed from the end of the list.\
	\
	The UndoManager can be instructed to free target or argument data when records are removed from the undoList (whether they fall off the end of the list or are executed during an undo command). This is achieved by the -freeUndoTarget and -freeUndoArgs methods. Additionally the -copyUndoArgs method will copy any pointers that are registered with the next message (it is then assumed that the UndoManager will free them).\
	\
	To trigger an Undo record, simply call -undo. This places the UndoManager into a "redo" state. All messages that are registered during an Undo are kept in a "redo" list. Thus the undo manager provides for redo as well. Redo can be triggered with the -redo message. The redo list is emptied each time a new record is added to the undo list (because, redo should only work if there were previous undos).\
\
	Clients of the undoManager can be notified when an undo is executed by adding themselves to the UndoManager's delegate list(-addUndoDelegate:). The only notification messages are -undoManagerWillUndo: and -undoManagerDidUndo: (called before and after an undo or redo). This notification is useful to do perform functions that all undo events may require, like calling -display.\
\
Written by: Jeff Martin (jmartin@bozell.com)\
You may freely copy, distribute and reuse the code in this example.  \
Don't even talk to me about warranties.\
******************************************************************************/\

\gray0\fc0\cf0 \

\gray300\fc2\cf2 #ifdef hppa\

\gray0\fc0\cf0 #define TARGET(UndoRec)	(*(id *)(UndoRec->args+UndoRec->argSize-4))\
#define SELECTOR(UndoRec)	(*(SEL *)(UndoRec->args+UndoRec->argSize-8))\

\gray300\fc2\cf2 #else\

\gray0\fc0\cf0 #define TARGET(UndoRec)	(*(id *)UndoRec->args)\
#define SELECTOR(UndoRec)	(*(SEL *)(UndoRec->args+4))\

\gray300\fc2\cf2 #endif\

\gray0\fc0\cf0 \
#define BIT(x) (((unsigned int)1)<<(x))\
#define BITS(from, to) ((((BIT(to) - 1)<<1) + 1) & !(BIT(from) - 1))\
\
id undoManager = NULL;\
\

\b @implementation UndoManager\

\b0 \
- 
\b init
\b0 \
\{\
	[super init];\
	undoList = [[List allocFromZone:[self zone]] init];\
	redoList = [[List allocFromZone:[self zone]] init];\
	delegateList = [[List allocFromZone:[self zone]] init];\
	disabled = NO; undoing = NO; redoing = NO;\
	levelsOfUndo = 99;\
	target = NULL; freeArgsMask = copyArgsMask = 0;\
	return self;\
\}\
\
\

\gray108\fc1\cf1 /******************************************************************************\
	- beginUndoRecordGrouping, - endUndoRecordGrouping\
	\
	These methods allow the client of the UndoManager to place several undo records in one undo "event". Undo messages that are received while not surrounded by begin/end undoRecordGrouping are placed into the undo list individually.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b beginUndoRecordGrouping
\b0 \
\{\
	if((!recordGrouping++) && (!disabled)) \{\
\

\gray300\fc2\cf2 		// Get the appropriate list\

\gray0\fc0\cf0 		id list = undoing? redoList :undoList;\
		id recordGroup = [[Storage allocFromZone:[self zone]] initCount:0 \
			elementSize: sizeof(UndoRecord) description:@encode(UndoRecord)];\
		\

\gray300\fc2\cf2 		// Add new recordGroup to the list if there is not an empty one there\

\gray0\fc0\cf0 		if(![list objectAt:0] || [[list objectAt:0] count]) \{\
			[list insertObject:recordGroup at:0];\
				\

\gray300\fc2\cf2 			// If list has more elements than levelsOfUndo, remove one from end\

\gray0\fc0\cf0 			if([list count] > levelsOfUndo) [self discardRecordGroup:\
				[list removeObjectAt:[list count]-1]];\
		\}\
	\}\
	return self;\
\}\
\
- 
\b endUndoRecordGrouping
\b0  \{ recordGrouping--; return self; \}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- disableUndoRegistration, - reenableUndoRegistration\
	\
	These methods allow the undomanager to ignore events. This is useful in a case like mouse dragging, where the application only wants the final move to be undoable and not all of the intermediate drags. These should be strategically placed in blocks and can be nested.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b disableUndoRegistration
\b0  \{ disabled++; return self; \}\
- 
\b reenableUndoRegistration
\b0  \{ disabled--; return self; \}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- setUndoTarget:object\
	\
	This method sets the target of following undo records. This is necessary because the sender cannot be gleaned from the forward method. Returns self.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b setUndoTarget
\b0 :
\i object
\i0  \{ target = object; return disabled? NULL : self; \}\

\gray108\fc1\cf1 /******************************************************************************\
	- freeUndoTarget, - freeUndoArgs, - freeUndoArgAt:(int)pos\
\
	These methods specify whether the UndoManager should free the target and/or its args when an undo record is executed or when it exceeds the number of levels of undo. These methods set bits in the freeArgsMask representing the argument position. Position 0 is the target. Position 1-15 represent the first 15 arguments to the method. Bits 0-15 in the freeArgsMask represent args to be freed when the record is discarded, while Bits 16-31 represent args to be freed when the record is executed.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b freeUndoTarget
\b0  \{ freeArgsMask |= BIT(0)|BIT(16); return self; \}\
- 
\b freeUndoArgs
\b0  \{ freeArgsMask |= ((-1) & (!BIT(0)) & (!BIT(16))); return self; \}\
- 
\b freeUndoArgAt
\b0 :(int)pos \{ freeArgsMask |= (BIT(pos)|BIT(pos+16));return self; \}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- freeUndoTargetOnRecordDiscard, - freeUndoArgsOnRecordDiscard,\
	- freeUndoArgOnRecordDiscardAt:(int)pos\
\
	These methods specify whether the UndoManager should free the target and/or its args when an undo record exceeds the number of levels of undo. These methods set bits 0 - 15 in the freeArgsMask representing the argument position. Position 0 is the target. Position 1-15 represent the first 15 arguments to the method.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b freeUndoTargetOnRecordDiscard
\b0  \{ freeArgsMask |= BIT(0); return self; \}\
- 
\b freeUndoArgsOnRecordDiscard
\b0  \{ freeArgsMask |= BITS(1,15); return self; \}\
- 
\b freeUndoArgOnRecordDiscardAt
\b0 :(int)pos\
\{ freeArgsMask |= BIT(pos); return self; \}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- freeUndoTargetOnRecordExecute, - freeUndoArgsOnRecordExecute,\
	- freeUndoArgOnRecordExecuteAt:(int)pos\
\
	These methods specify whether the UndoManager should free the target and/or its args when an undo record is executed. These methods set bits 16 - 31 in the freeArgsMask representing the argument position. Position 16 is the target. Position 17-31 represent the first 15 arguments to the method.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b freeUndoTargetOnRecordExecute 
\b0 \{ freeArgsMask |= BIT(16); return self; \}\
- 
\b freeUndoArgsOnRecordExecute
\b0  \{ freeArgsMask |= BITS(17,31); return self; \}\
- 
\b freeUndoArgOnRecordExecuteAt
\b0 :(int)pos\
\{ freeArgsMask |= BIT(pos+16); return self; \}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- copyUndoArgs, - copyUndoArgsAt:(int)pos\
\
	copyUndoArgs and copyUndoArgsAt: tell the UndoManager to copy pointer arguments(like objects or strings) for convenience. It is assumed that the UndoManager will free them when the undoRecord is freed. Returns self.\
	copyUndoArgsFreeOnDiscard and copyUndoArgsFreeOnExecute are just like copyUndoArgs but they specify whether to free the args when the record is discarded or when it is executed. They all Return self.\
******************************************************************************/\

\gray0\fc3\cf3 - 
\b copyUndoArgs
\b0  \{ copyArgsMask = -1
\fc0\cf0 ;
\fc3\cf3  [self freeUndoArgs]; return self; \}\
- 
\b copyUndoArgAt
\b0 :(int)
\i pos
\i0 \
\{ copyArgsMask |= 
\fc0\cf0 BIT(pos);
\fc3\cf3  [self freeUndoArgAt:pos]; return self; \}\
\
- 
\b copyUndoArgsFreeOnDiscard
\b0 \
\{ [self copyUndoArgs]
\fc0\cf0 ;
\fc3\cf3  [self freeUndoArgsOnRecordDiscard]; return self; \}\
- 
\b copyUndoArgFreeOnDiscardAt
\b0 :(int)
\i pos
\i0 \
\{ [self copyUndoArgAt:pos]
\fc0\cf0 ;
\fc3\cf3 [self freeUndoArgOnRecordDiscardAt:pos];return self;\}\
\
- 
\b copyUndoArgsFreeOnExecute
\b0 \
\{ [self copyUndoArgs]
\fc0\cf0 ;
\fc3\cf3  [self freeUndoArgsOnRecordDiscard]; return self; \}\
- 
\b copyUndoArgFreeOnExecuteAt
\b0 :(int)
\i pos
\i0 \
\{ [self copyUndoArgAt:pos]
\fc0\cf0 ;
\fc3\cf3 [self freeUndoArgOnRecordDiscardAt:pos];return self;\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- copyUndoArgsForRecord:(UndoRecord *)undoRecord\
\
	copyUndoArgsForRecord is used internally and does the actual work of copying the pointers.\
******************************************************************************/\

\gray0\fc3\cf3 - 
\b copyUndoArgsForRecord
\b0 :(UndoRecord *)
\i undoRecord
\i0 \

\fc0\cf0 \{\
\
	Method	method = class_getInstanceMethod([TARGET(undoRecord) class],\
		SELECTOR(undoRecord));\
	int argCount = method_getNumberOfArguments(method);\
	int i, offset;\
	char *type;\
\

\gray300\fc2\cf2 	// Copy the target if requested\

\gray0\fc0\cf0 	if(copyArgsMask & BIT(0)) TARGET(undoRecord) =\
		[TARGET(undoRecord) copyFromZone:[self zone]];\
	\

\gray300\fc2\cf2 	// Copy each argument that the client requested\

\gray0\fc0\cf0 	for(i=2; i<argCount; i++) if(copyArgsMask & BIT(i-1)) \{\

\gray300\fc2\cf2 \
		// Get argument type and offset\

\gray0\fc0\cf0 		method_getArgumentInfo(method, i, &type, &offset);\

\gray300\fc2\cf2 #ifdef hppa\

\gray0\fc0\cf0 		offset += undoRecord->argSize;\

\gray300\fc2\cf2 #endif
\gray0\fc0\cf0 \
		\

\gray300\fc2\cf2 		// If argument is a string copy with NXCopyStringBufferFromZone\

\gray0\fc0\cf0 		if(!strncmp(type,"*",1)) \{\
			char **stringPtr = (char **)(undoRecord->args+offset);\
			*stringPtr = (*stringPtr)? \
				NXCopyStringBufferFromZone(*stringPtr, [self zone]) : NULL;\
		\}\
		\

\gray300\fc2\cf2 		// If argument is an object copy with -copyFromZone:\

\gray0\fc0\cf0 		if(!strncmp(type,"@",1)) \{\
			id *objectPtr = (id *)(undoRecord->args+offset);\
			*objectPtr = [*objectPtr copyFromZone:[self zone]];			\
		\}\
	\}\
	return self;\
\}\

\gray108\fc1\cf1 \
/******************************************************************************\
	- forward:(SEL)aSelector :(marg_list)argFrame\
	\
	This method is how events are registered with the Undo Manager. When the UndoManager receives a message that it doesn't respond to, it assumes that this is an undo event and associates it with the current target. This undoRecord is then added to the undoList.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b forward
\b0 :(SEL)
\i aSelector
\i0  :(marg_list)
\i argFrame
\i0 \
\{\

\gray300\fc2\cf2 	// Register the event if we are not disabled and there is a current target\

\gray0\fc0\cf0 	if((!disabled) && target) \{\
\

\gray300\fc2\cf2 		// Allocate a new undo record and set its fields\

\gray0\fc0\cf0 		UndoRecord *undoRecord = NXZoneMalloc([self zone], sizeof(UndoRecord));\
		int argSize = method_getSizeOfArguments(\
			class_getInstanceMethod([target class], aSelector));\
		undoRecord->freeArgsMask = freeArgsMask;\
		undoRecord->argSize = argSize;\

\gray300\fc2\cf2 		\
		// Make a copy of the arguements (copy deep if requested)\

\gray0\fc0\cf0 		undoRecord->args = NXZoneMalloc([self zone], argSize);\

\gray300\fc2\cf2 #ifdef hppa\

\gray0\fc0\cf0 		bcopy(argFrame - argSize, undoRecord->args, argSize);\

\gray300\fc2\cf2 #else\

\gray0\fc0\cf0 		bcopy(argFrame, undoRecord->args, argSize);\

\gray300\fc2\cf2 #endif\

\gray0\fc0\cf0 		TARGET(undoRecord) = target;\

\fc3\cf3 		if(copyArgsMask) [self copyUndoArgsForRecord:undoRecord];\

\fc0\cf0 \

\gray300\fc2\cf2 		// Do implicit recordGrouping if needed\

\gray0\fc3\cf3 		if(!recordGrouping) [[self beginUndoRecordGrouping]\
			endUndoRecordGrouping];\
			\

\fc0\cf0 		if(undoing) [[redoList objectAt:0] addElement:undoRecord];\
		else [[undoList objectAt:0] addElement:undoRecord];\
\

\gray300\fc2\cf2 		// Make sure that redo list is empty if in normal mode.\

\gray0\fc0\cf0 		if(!undoing && !redoing) while([redoList count])\
			[self discardRecordGroup:[redoList removeObjectAt:0]];\
	\}\
	\

\gray300\fc2\cf2 	// Reset registration masks\

\gray0\fc0\cf0 	freeArgsMask = 0; copyArgsMask = 0;\
	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- undo:sender\
	\
	This message actually triggers the UndoManager to take the top undo record and send out all of the events. The record is then freed.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b undo
\b0 :
\i sender
\i0 \
\{\
	id recordGroup = [undoList removeObjectAt:0];\
	\

\gray300\fc2\cf2 	// Get the last list that actually had undo records in it\

\gray0\fc0\cf0 	while(recordGroup && ![recordGroup count]) \
		recordGroup = [undoList removeObjectAt:0];\
	\
	
\gray300\fc2\cf2 // Beep if there was no record group
\gray0\fc0\cf0 \
 	if(!recordGroup) NXBeep();\

\gray300\fc2\cf2 \
	// Otherwise set undo flag, execute record group, reset undo flag & return\

\gray0\fc3\cf3 	else \{ 
\fc0\cf0 undoing = YES; [self executeRecordGroup:recordGroup]; undoing = NO; \}\
	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- redo\
	\
	This message actually triggers the UndoManager to take the top redo record and send out all of the events. The record is then freed.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b redo
\b0 :
\i sender
\i0 \
\{\
	id recordGroup = [redoList removeObjectAt:0];\
	\

\gray300\fc2\cf2 	// Get the last list that actually had undo records in it\

\gray0\fc0\cf0 	while(recordGroup && ![recordGroup count]) \
		recordGroup = [redoList removeObjectAt:0];\
\
	
\gray300\fc2\cf2 // Beep if there was no record group
\gray0\fc0\cf0 \
 	if(!recordGroup) NXBeep();\

\gray300\fc2\cf2 \
	// Otherwise set redo flag, execute record group, reset redo flag & return\

\gray0\fc3\cf3 	else \{ 
\fc0\cf0 redoing = YES; [self executeRecordGroup:recordGroup]; redoing = NO; \}\
	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- (int)levelsOfUndo, - setLevelsOfUndo:(int)value\
	\
	These methods allow programmatic manipulation for the levels of undo that an UndoManager maintains.\
******************************************************************************/\

\gray0\fc0\cf0 - (int)
\b levelsOfUndo
\b0  \{ return levelsOfUndo; \}\
- 
\b setLevelsOfUndo
\b0 :(int)
\i value
\i0  \{ levelsOfUndo = value; return self; \}\
\
\

\gray108\fc1\cf1 /******************************************************************************\
	- addUndoDelegate:object, - removeUndoDelegate:object\
	\

\pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\gray108\fc1\cf1 	These methods add and remove objects that are to receive undo notification. The two notifications that are currently supported are undoManagerWillUndo: and undoManagerDidUndo (sent before and after an Undo or Redo).\

\pard\tx540\tx1080\tx1620\tx2160\tx2700\tx3240\tx3780\tx4320\tx4860\tx5400\tx5940\tx6480\tx7020\tx7560\tx8100\tx8640\tx9180\tx9720\tx10260\tx10800\tx11340\gray108\fc1\cf1 ******************************************************************************/\

\gray0\fc0\cf0 - 
\b addUndoDelegate
\b0 :
\i object
\i0  \{ [delegateList addObject:object]; return self; \}\
- 
\b removeUndoDelegate
\b0 :
\i object
\i0  \{ [delegateList removeObject:object]; return self; \}\
- 
\b sendNotification
\b0 :(SEL)
\i action
\i0 \
\{\
	int i; for(i=0; i<[delegateList count]; i++)\
		if([[delegateList objectAt:i] respondsTo:action])\
			[[delegateList objectAt:i] perform:action with:self];\
	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- discardRecordGroup:recordGroup;\
	- executeRecordGroup:recordGroup;\
	- freeUndoRecord:(UndoRecord *)undoRecord;\
	\
	These methods free the individual records in a record group. discardRecordGroup: calls freeUndoRecord:withMask: with the discard part of the freeArgsMask while executeRecordGroup: executes the records in the record group then calls freeUndoRecord:withMask: with the execute part of the the freeArgsMask.\
	freeUndoRecord walks through the record arguments free those that the freeMask requests to be freed. Returns self.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b discardRecordGroup
\b0 :
\i list
\i0 \
\{\
	int i;\
	\
	
\gray300\fc2\cf2 // Free the records in the list, then the list\

\gray0\fc0\cf0 	for(i=0; i<[list count]; i++)\
		[self freeUndoRecord:[list elementAt:i] withFreeMask:freeArgsMask];\
	[list free];\
	return self;\
\}\
\
- 
\b executeRecordGroup
\b0 :
\i recordGroup
\i0 \
\{\
	int i;\
	\

\gray300\fc2\cf2 	// Send WillUndo notification\

\gray0\fc0\cf0 	[self sendNotification:@selector(undoManagerWillUndo:)];\

\gray300\fc2\cf2 \
	// Start undo record grouping, execute & free records & stop record grouping\

\gray0\fc0\cf0 	[self beginUndoRecordGrouping];\
	for(i=0; i<[recordGroup count]; i++) \{\
		UndoRecord *rec = [recordGroup elementAt:i];\

\gray300\fc2\cf2 #ifdef hppa\

\gray0\fc0\cf0 		[TARGET(rec) performv:SELECTOR(rec) :rec->args + rec->argSize];\

\gray300\fc2\cf2 #else\

\gray0\fc0\cf0 		[TARGET(rec) performv:SELECTOR(rec) :rec->args];\

\gray300\fc2\cf2 #endif\

\gray0\fc0\cf0 		[self freeUndoRecord:rec withFreeMask:(rec->freeArgsMask>>16)];\
	\}\
	[self endUndoRecordGrouping];\
\

\gray300\fc2\cf2 	// Send DidUndo notification and return\

\gray0\fc0\cf0 	[self sendNotification:@selector(undoManagerDidUndo:)];\
	return self;\
\}\
\
- 
\b freeUndoRecord
\b0 :(UndoRecord *)
\i undoRecord
\i0  
\b withFreeMask
\b0 :(int)free
\i Mask
\i0 \
\{\
    Method	method = class_getInstanceMethod([TARGET(undoRecord) class],\
    	SELECTOR(undoRecord));\
	int argCount = method_getNumberOfArguments(method);\
	int i, offset;\
	char *type;\
	\

\gray300\fc2\cf2 	// Free the target if requested\

\gray0\fc0\cf0 	if(freeMask & BIT(0)) [TARGET(undoRecord) free];\
	\

\gray300\fc2\cf2 	// Free anything that the args point to if requested\

\gray0\fc0\cf0 	for(i=2; i<argCount; i++) if(freeMask & BIT(i-1)) \{\
	\
			method_getArgumentInfo(method, i, &type, &offset);\

\gray300\fc2\cf2 #ifdef hppa\

\gray0\fc0\cf0 			offset += undoRecord->argSize;\

\gray300\fc2\cf2 #endif
\gray0\fc0\cf0 \
			\

\gray300\fc2\cf2 		// Free any strings or pointers with free() function\

\gray0\fc0\cf0 		if(!strncmp(type,"*",1)) free(*(char **)(undoRecord->args+offset));\
			\

\gray300\fc2\cf2 		// Free any objects with -free method\

\gray0\fc0\cf0 		else if(!strncmp(type,"@",1)) [*(id *)(undoRecord->args+offset) free];			\
	\}\
\

\gray300\fc2\cf2 	// Free the args\

\gray0\fc0\cf0 	free(undoRecord->args);\

\gray300\fc2\cf2 \

\gray0\fc0\cf0 	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- emptyUndoManager\
	\
	emptyUndoManager removes all of the recordGroups from the undoList and redoList. An UndoManager client might do this when a document is saved. Returns self.\
******************************************************************************/\

\gray0\fc3\cf3 - 
\b emptyUndoManager
\b0 \
\{\

\fc0\cf0 	while([undoList count]) [self discardRecordGroup:\
		[undoList removeObjectAt:0]];\
	while([redoList count]) [self discardRecordGroup:\
		[redoList removeObjectAt:0]];\

\fc3\cf3 	return self;\
\}\
\

\gray108\fc1\cf1 /******************************************************************************\
	- free\
	\
	Frees each undo group in the undo and redo lists then it frees the undo and redo lists.\
******************************************************************************/\

\gray0\fc0\cf0 - 
\b free
\b0 \
\{\
	[self emptyUndoManager];\
	[undoList free]; [redoList free]; [delegateList free];\
	return [super free];\
\}\
\

\b @end
}
